package com.boot2.core.utils;

import com.google.common.collect.ImmutableMap;
import lombok.SneakyThrows;
import org.apache.commons.lang3.time.DateUtils;

import java.text.ParseException;
import java.util.Date;
import java.util.Map;

/**
 * @author zhangweilin
 * @Description: 时间范围工具
 * @date 2020/6/10
 */
public class TimeRangeUtil {

    private interface TimeAddHandler {
        Date hand(Date date, int num);
    }

    private static final Map<Integer, TimeAddHandler> timeAddHandlerMap = ImmutableMap.<Integer, TimeAddHandler>builder()
            .put(DateUtil.min, DateUtils::addMinutes)
            .put(DateUtil.hour, DateUtils::addHours)
            .put(DateUtil.day, DateUtils::addDays)
            .put(DateUtil.week, DateUtils::addWeeks)
            .put(DateUtil.month, DateUtils::addMonths)
            .put(DateUtil.year, DateUtils::addYears)
            .build();

    /**
     * 根据周期和差值求开始时间
     */
    private interface GetStartTimeByDiffValueHandler {
        Date hand(Date date, int startTime, int endTime);
    }

    private static final Map<Integer, GetStartTimeByDiffValueHandler> getStartTimeByDiffValueHandlerMap = ImmutableMap.<Integer, GetStartTimeByDiffValueHandler>builder()
            .put(DateUtil.min, (endTime, startTimeInt, endTimeInt) -> {
                //求分差值
                int diffMin = endTimeInt - startTimeInt;
                if (diffMin <= 0) {
                    diffMin = diffMin + 60;
                }
                Date startTime = DateUtil.addMin(endTime, -diffMin);
                return startTime;
            })
            .put(DateUtil.hour, (endTime, startTimeInt, endTimeInt) -> {
                //求小时差值，即前后相差小时数
                int diffHour = endTimeInt - startTimeInt;
                //如果小于等于0，表示endTimeInt为次日的，需要加24小时后再减  如 23到次日 05为6小时, 即29-23,根据等式，也即减后的值直接加24
                if (diffHour <= 0) {
                    diffHour = diffHour + 24;
                }
                Date startTime = DateUtil.addHour(endTime, -diffHour);
                return startTime;
            })
            .put(DateUtil.day, (endTime, startTimeInt, endTimeInt) -> {
                //求天差值，即前后相差天数
                int diffDay = endTimeInt - startTimeInt;
                Date startTime = DateUtil.setDay(endTime, startTimeInt);

                //如果小于等于0，表示开始日期为上个月,由于每月天数不统一，不能直接加减
                if (diffDay <= 0) {
                    startTime = DateUtil.addMonth(startTime, -1);
                }
                return startTime;
            })
            .put(DateUtil.week, (endTime, startTimeInt, endTimeInt) -> {
                //求天差值，即前后相差天数
                int diffWeekDay = endTimeInt - startTimeInt;
                //如果小于等于0，表示endTimeInt为次周的，需要加七天后再减,如周5到周1
                if (diffWeekDay <= 0) {
                    diffWeekDay = diffWeekDay + 7;
                }
                Date startTime = DateUtil.addDay(endTime, -diffWeekDay);
                return startTime;
            })
            .put(DateUtil.month, (endTime, startTimeInt, endTimeInt) -> {
                //求天差值，即前后相差天数
                int diffMonth = endTimeInt - startTimeInt;
                if (diffMonth <= 0) {
                    diffMonth = diffMonth + 12;
                }
                Date startTime = DateUtil.addMonth(endTime, -diffMonth);
                return startTime;
            })
            .put(DateUtil.year, (endTime, startTimeInt, endTimeInt) -> DateUtil.addYear(endTime, startTimeInt - endTimeInt))
            .build();


    /**
     * 根据统计精度和传入时间基数，计算统计的起始时间
     *
     * @param startTime
     * @param downsample 统计的精度 0:sys_date_hour_minute 1:sys_date_hour  2:sys_date_day 3:sys_date_week,4:sys_date_month,5:sys_date_year
     * @return
     * @throws ParseException
     */
    @SneakyThrows
    public static Date getStartDateTime(String startTime, int downsample) {
        Date startDateTime = DateUtils.parseDate(startTime, "yyyyMMdd");
        return timeAddHandlerMap.get(downsample).hand(startDateTime, -1);
    }

    /**
     * 根据统计精度和传入时间基数，计算统计的起始时间
     *
     * @param startTime
     * @param downsample 统计的精度 0:sys_date_hour_minute 1:sys_date_hour  2:sys_date_day 3:sys_date_week,4:sys_date_month,5:sys_date_year
     * @return
     * @throws ParseException
     */
    @SneakyThrows
    public static Date getStartDateTime(Date startTime, int downsample) {
        return timeAddHandlerMap.get(downsample).hand(startTime, -1);
    }

    /**
     * 根据统计精度和传入时间基数，计算统计的起始时间
     *
     * @param startTime
     * @param downsample 统计的精度 0:sys_date_hour_minute 1:sys_date_hour  2:sys_date_day 3:sys_date_week,4:sys_date_month,5:sys_date_year
     * @return
     * @throws ParseException
     */
    @SneakyThrows
    public static Date getStartDateTime(Date startTime, int downsample, int diffValue) {
        return timeAddHandlerMap.get(downsample).hand(startTime, diffValue);
    }

    /**
     * 根据统计精度和传入时间基数，计算统计的起始时间
     *
     * @param startTime
     * @param downsample 统计的精度 0:sys_date_hour_minute 1:sys_date_hour  2:sys_date_day 3:sys_date_week,4:sys_date_month,5:sys_date_year
     * @return
     * @throws ParseException
     */
    @SneakyThrows
    public static Date getEndDateTime(String startTime, int downsample, int span) {
        Date startDateTime = DateUtils.parseDate(startTime, "yyyyMMdd");
        return timeAddHandlerMap.get(downsample).hand(startDateTime, span);
    }

    /**
     * 根据统计精度和传入时间基数，计算统计的起始时间
     *
     * @param startTime
     * @param downsample 统计的精度 0:sys_date_hour_minute 1:sys_date_hour  2:sys_date_day 3:sys_date_week,4:sys_date_month,5:sys_date_year
     * @return
     * @throws ParseException
     */
    @SneakyThrows
    public static Date getEndDateTime(Date startTime, int downsample, int span) {
        return timeAddHandlerMap.get(downsample).hand(startTime, span);
    }


    /**
     * 按精度加减时间
     *
     * @param date
     * @param downSample
     * @param num
     * @return
     */
    public static Date add(Date date, int downSample, int num) {
        return timeAddHandlerMap.get(downSample).hand(date, num);
    }

    /**
     * 按精度加减时间
     *
     * @param date
     * @param downSample
     * @param num
     * @return
     */
    public static String addForStr(Date date, int downSample, int num) {
        Date date2 = timeAddHandlerMap.get(downSample).hand(date, num);
        return DateUtil.formatDate(date2);
    }

    /**
     * 按精度加减时间
     *
     * @param date
     * @param downSample
     * @param num
     * @return
     */
    public static String addForStr(Date date, String pattern, int downSample, int num) {
        Date date2 = timeAddHandlerMap.get(downSample).hand(date, num);
        return DateUtil.formatDate(date2, pattern);
    }


    /**
     * 根据不同的精度（周期）和给出的前后差值，求不同的开始时间
     *
     * @param downSample
     * @param date
     * @param startTime
     * @param endTime
     * @return
     */
    public static Date getStartTimeByDiffValue(int downSample, Date date, int startTime, int endTime) {
        return getStartTimeByDiffValueHandlerMap.get(downSample).hand(date, startTime, endTime);
    }

    /**
     * 分项页面查询条件，自定义时间，时:1, 日:2,周:3, 月:4,年:5
     */
    private static final ImmutableMap<Integer, ImmutableMap<String, String>> timeRangeTypeMap = ImmutableMap.<Integer, ImmutableMap<String, String>>builder()
            .put(DateUtil.min, ImmutableMap.of("sysDateTableName", "sys_date_hour_minute", "dateaddStep", "minute"))
            .put(DateUtil.hour, ImmutableMap.of("sysDateTableName", "sys_date_hour", "dateaddStep", "hour"))
            .put(DateUtil.day, ImmutableMap.of("sysDateTableName", "sys_date_day", "dateaddStep", "day"))
            .put(DateUtil.week, ImmutableMap.of("sysDateTableName", "sys_date_week", "dateaddStep", "week"))
            .put(DateUtil.month, ImmutableMap.of("sysDateTableName", "sys_date_month", "dateaddStep", "month"))
            .put(DateUtil.year, ImmutableMap.of("sysDateTableName", "sys_date_year", "dateaddStep", "year"))
            .build();

    public static Map<String, String> getTimeRangeTypeMap(Integer key) {
        return timeRangeTypeMap.get(key);
    }

    /**
     * 分项页面查询条件，自定义时间，时:1, 日:2,周:3, 月:4,年:5
     */
    private static final ImmutableMap<Integer, String> timeRangeNameMap = ImmutableMap.<Integer, String>builder()
            .put(DateUtil.min, "Minute")
            .put(DateUtil.hour, "Hour")
            .put(DateUtil.day, "Day")
            .put(DateUtil.week, "Week")
            .put(DateUtil.month, "Month")
            .put(DateUtil.year, "Year")
            .build();

    public static String getTimeRangeNameMap(Integer key) {
        return timeRangeNameMap.get(key);
    }

    /**
     * 分项页面查询条件，自定义时间，时:1, 日:2,周:3, 月:4,年:5
     */
    private static final ImmutableMap<Integer, String> intervalMap = ImmutableMap.<Integer, String>builder()
            .put(DateUtil.min, "m")
            .put(DateUtil.hour, "h")
            .put(DateUtil.day, "d")
            .put(DateUtil.week, "w")
            .put(DateUtil.month, "mo")
            .put(DateUtil.year, "y")
            .build();

    public static String getInterval(Integer key, int step) {
        return step + intervalMap.get(key);
    }

}
